package com.my.thread.syncRetuen;

import com.alibaba.fastjson.JSON;
import com.my.thread.syncRetuen.service.SpringThreadService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class SimpleTests {

    @Autowired
    private SpringThreadService service;

    @Test
    public void contextLoads() {
    }

    /**
     * 没有返回值测试
     */
    @Test
    public void testVoid() {
        for (int i = 0; i < 20; i++) {
            service.excutVoidTask(i);
        }
        System.out.println("========主线程执行完毕=========");
    }

    @Test
    public void testReturn() throws InterruptedException, ExecutionException {
        List<Future<String>> lstFuture = new ArrayList<>();// 存放所有的线程，用于获取结果
        for (int i = 0; i < 100; i++) {
            while (true) {
                try {
                    // 线程池超过最大线程数时，会抛出TaskRejectedException，则等待1s，直到不抛出异常为止
                    Future<String> stringFuture = service.excuteValueTask(i);
                    lstFuture.add(stringFuture);
                    break;
                } catch (TaskRejectedException e) {
                    System.out.println("线程池满，等待1S。");
                    Thread.sleep(1000);
                }
            }
        }

        // 获取值.get是阻塞式，等待当前线程完成才返回值
        for (Future<String> future : lstFuture) {
            System.out.println(future.get());
        }

        System.out.println("========主线程执行完毕=========");
    }

    /*彩蛋——Future<T>使用lambda表达式*/
//    public void sendMail(Map<String, Object> model, String title, String templateName, String toMail, String[] ccMail, long timeout) throws Exception {
//        Future<String> submit;
//        submit = emailServiceExecutor.submit(() ->{
//            try {
//                return "s";
//            } catch (Exception e) {
//                return "F";
//            }
//        });
//    }
    /*若自定义实现线程池，如何获取到各个任务的结果*/
    /*若是我们自己实现线程池，可以使用java.util.concurrent.AbstractExecutorService#invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>)
    方法进行定时任务的批量处理，返回值其实是List<Future<T>>，我们可以循环遍历该List，最终拿到各个任务的执行结果。*/
    @Test
    public void test() throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60,
                TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(9));
        //需要执行的任务
        List<String> students= new ArrayList<String>(5);
        students.add("1");
        students.add("1");
        students.add("1");
        students.add("1");
        students.add("1");
        students.add("1");
        students.add("1");
        //将任务转换为Callable对象
        List<Callable<Integer>> callables = new ArrayList<>();
        //保存返回结果
        List<Integer> results=new ArrayList<>();
        //开启线程,lambda表达式
        for (String s : students) {
            callables.add(()->{
                //插入操作,并发执行
                log.info(JSON.toJSONString(s));
                //表示异步操作
//                int save = serviceImpl.getStu(student);
                //返回值
                return 1 ;
            });
        }
        //获取到所有任务的处理结果
        List<Future<Integer>> futures = executor.invokeAll(callables);
        //遍历每个任务的执行结果，每次future.get()只有在任务执行完毕后，才会继续循环操作，否则会阻塞，等待线程执行结束
        for (Future<Integer> future:futures){
            try {
                results.add(future.get());
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        executor.shutdown();  //关闭线程池
        log.info("数据执行完毕！{}",JSON.toJSONString(results));
    }

}
